package com.xiaoma.socket

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.util.Log
import androidx.core.content.getSystemService
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import java.net.Inet4Address
import java.net.Inet6Address

object NetworkStateWatcher {
    private val TAG = "${NetworkStateWatcher::class.simpleName}Tag"

    private val appScope = ProcessLifecycleOwner.get().lifecycleScope
    private val manager = MutableStateFlow<ConnectivityManager?>(null)
    private val network = MutableStateFlow<Network?>(null)

    fun prepare(context: Context) {
        manager.update { context.getSystemService<ConnectivityManager>() }
        manager.value?.let { cm ->
            Log.i(TAG, "registerDefaultNetworkCallback")
            cm.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(n: Network) = network.update { n }
                override fun onLost(n: Network) = network.update { null }
                override fun onUnavailable() = network.update { null }
            }
            )
        }
    }

    val ipAddresses = combine(
        manager,
        network,
        ::Pair
    ).mapLatest { (cm, n) ->
        cm?.let {
            it.getLinkProperties(n)?.linkAddresses
        }?.let { list ->
            list.map { it.address }
                .filterNot { it.isAnyLocalAddress }
                .mapNotNull {
                    val type = when (it) {
                        is Inet4Address -> "IPv4"
                        is Inet6Address -> "IPv6"
                        else -> "Unknown"
                    }
                    val host = it.hostAddress ?: ""
                    Address(type, host)
                }
        } ?: emptyList()
    }.onEach {
        Log.i(TAG, "each ip address: $it")
    }.stateIn(appScope, SharingStarted.Eagerly, emptyList())
}